#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
using namespace std;

//环形队列默认大小
#define N 5

//信号量


template<class T>
class RingQueue{
private:
    void P(sem_t &s){
        sem_wait(&s);
    }

    void V(sem_t &s){
        sem_post(&s);
    }

    void Lock(pthread_mutex_t& m){
        pthread_mutex_lock(&m);
    }

    void Unlock(pthread_mutex_t& m){
        pthread_mutex_unlock(&m);
    }

public:
    RingQueue(int num = N): _ring(num), _cap(num){
        sem_init(&_data_sem, 0, 0);
        sem_init(&_space_sem, 0, num);
        _c_step = _p_step = 0;

        pthread_mutex_init(&_c_mtx, nullptr);
        pthread_mutex_init(&_p_mtx, nullptr);
    }

    //生产
    void push(const T& in){
        
        P(_space_sem);
        Lock(_p_mtx);
        //走到这里一定有对应的资源，不用判断

        //当队列为空，_data_sem==0，_space_sem==num，
        //由于信号量的存在，能够保证队列为空时生产者先运行，队列满时消费者先运行
        _ring[_p_step++] = in;
        //_p_step不能超过_cap
        _p_step %= _cap;

        Unlock(_p_mtx);
        V(_data_sem);
        
    }

    void pop(T *out){

        P(_data_sem);
        Lock(_c_mtx);

        *out = _ring[_c_step++];
        _c_step %= _cap;

        Unlock(_c_mtx);
        V(_space_sem);
    }

    ~RingQueue(){
        sem_destroy(&_data_sem);
        sem_destroy(&_space_sem);

        pthread_mutex_destroy(&_c_mtx);
        pthread_mutex_destroy(&_p_mtx);

    }

private:
    vector<T> _ring;

    int _cap;           //环形队列的大小
    sem_t _data_sem;    // 只有消费者关心
    sem_t _space_sem;   //只有生产者关心
    int _c_step;         //消费位置
    int _p_step;        //生产位置

    pthread_mutex_t _p_mtx;
    pthread_mutex_t _c_mtx;
};